/*******************************************************************************
 * 版权：北京润尼尔网络科技有限公司，保留所有版权<br>
 * 版本：v1.0.0<br>
 * 文件：CommandPaste.js<br>
 * 日期：2016年9月29日<br>
 * 作者: 王志远<br>
 * 功能：粘贴命令<br>
 * 
 * 修改记录：<br>
 * 日期 描述 更新功能<br>
 ******************************************************************************/

window.makeNamespace(window,"Rainier.UI.V2");

/**
 * 类型名称：Rainier.UI.V2.CommandPaste<br>
 * 类型功能：粘贴命令<br>
 */
Rainier.UI.V2.CommandPaste = draw2d.command.Command.extend({
	
	NAME : "Rainier.UI.V2.CommandPaste",
	
	/**
	 * 函数名称：Rainier.UI.V2.CommandPaste.init<br>
	 * 函数功能：构造函数<br>
	 * 异常信息：无<br>
	 */
	init : function(context){
		this._super();
		this.context 	  	= context;
		this.rootEditPart 	= this.context.getRootEditPart();
		this.rootFigure   	= this.context.getRootFigure();
		this.rootModel    	= this.context.getRootModel();

		this.modelList 		= this.context.copyModelList;
		this.connList	   	= new draw2d.util.ArrayList();
		this.newModelList	= new draw2d.util.ArrayList();
		if(this.modelList.getSize()<1){
			//如果modelList的size为0，则直接返回，什么都不做
			return;
		}
		
		this.editParts 		= new draw2d.util.ArrayList();
		this.deviceList 	= new draw2d.util.ArrayList();
		this.copyInfoList	= new draw2d.util.ArrayList();

		this.sortModels();
		
    	this.offset			= 20;
    	this.deleteCmd 		= null;
    	
    	this.mouseDownPos   = this.caculateModelOffset();
	},
	
	/**
	 * 函数名称：Rainier.UI.V2.CommandCopy.getModelsCopy<br>
	 * 函数功能：对连线进行特殊处理，所有连接端口重置为其副本<br>
	 * 参数输入：editParts ：Rainier.UI.V2.AbstractEditPart数组<br>
	 * 参数输出：无<br>
	 * 函数返回：无<br>
	 * 异常信息：无<br>
	 */
	getModelsCopy : function(modelList){
		
		var _this = this;
		modelList.each(function(j,model){
			var newModel    = model.clone();			
			_this.newModelList.add(newModel);
		})
		
		modelList.each(function(j,model){
			model.clearDuplicate();
		})
		
		//此处需要修改，最好在鼠标点击处，创建对应需要粘贴的元件
		//将被复制对象重置为已复制对象 ，主要用于位置偏移
		this.context.copyModelList = this.newModelList;
	},
	
	/**
	 * 函数名称：Rainier.UI.V2.CommandDeleteMulti.sortEditParts<br>
	 * 函数功能：整理多个选择元器件<br>
	 * 对于元件的复制 粘贴过程的分析如下：把器件和连线分成两步进行完成
	 * 1、首先处理选中的所有 元器件，删除器件上关联的连线，把需要复制的器件保存到对应的数组中
	 * 2、其次处理选中的所有 连线:
	 * 	  对于连线，采用和删除时相同的方法
	 * 对于粘贴的undo操作
	 * 即创建元件的删除过程,由于连线不会孤立存在，所以我们创建的连线都和我们穿件的model是相关联的
	 * 我们删除元件的时候，同时会删除掉与当前元件相关的连线，当元件删除完成时，连线会自动删除。
	 * 此处调用deleteCommand命令，完成单个元件的删除，恢复时，可以使用deleteCommand的redo操作完成。
	 * 
	 * 参数输入：无<br>
	 * 参数输出：无<br>
	 * 函数返回：无<br>
	 * 异常信息：无<br>
	 */
	sortModels : function(){
		var _this = this;
		this.getModelsCopy(this.modelList);
		//将modelList中的model进行分类处理
		this.newModelList.each(function(j,model){
			if(model instanceof Rainier.UI.V2.DeviceModel){
				model.connections.clear();
				_this.deviceList.add(model);
			}
			else if(model instanceof Rainier.UI.V2.ConnectionModel){
				_this.connList.add(model);
			}
		});
		
		var connListCopy = _this.connList.clone();
		
		//使用连线副本完成对连线信息储存
		while(connListCopy.getSize()>0){
			for(var i = 0;i<connListCopy.getSize();i++){
				var conn 		= connListCopy.get(i);
				var jointModels = conn.getChildren();
				
				//判断子节点上的连线是否被选中，若选中则什么都不做，若未选中，则直接删除
				$.each(jointModels,function(index,jointModel){
					var hybirdPort = jointModel.getHybridPorts().get(0);
					var incomings  = hybirdPort.getIncomings();
					var outgoings  = hybirdPort.getOutgoings();
					var jointConns = incomings.addAll(outgoings,true);
					var size 	   = jointConns.getSize();
					//则判断当前连线的入读和出度 ，如果为1 则删除，如果不为1 则解除关联关系
					if(size === 0){
						var jointModelParent = jointModel.getParent();
						if(jointModelParent){
							jointModelParent.removeChildModel(jointModel);
						}
					}
				});
				
				//保存没有孩子的连线
				if(!jointModels.length){
					//把删除的信息，保存在堆栈中
					var connInfo		= conn.encapsulateConnInfo();
					_this.copyInfoList.push(connInfo);
					
					//根据连线类型，删除连线
					var connType  		= connInfo.connType;
					var connModel   	= connInfo.connModel;
					var sourceModel  	= connInfo.sourceModel;
					var targetModel		= connInfo.targetModel;
					
					var currentConn		= connModel.connection;
					
					//解除关联关系
					currentConn.detachSourcePortAndTargetPort();
					
					//根据jointModel是否存在，进行jointModel的删除
					if(sourceModel){
						var jointModel = sourceModel.jointModel;
						_this._removeJointModel(jointModel);
					}
					if(targetModel){
						var jointModel = targetModel.jointModel;
						_this._removeJointModel(jointModel);
					}
					
					connListCopy.removeElementAt(i);
					i--;
				}
			}
		}
	},
	
    /**
	 * 函数名称：Rainier.UI.V2.CommandPaste.canExecute<br>
	 * 函数功能：是否能够执行命令<br>
	 * 函数返回：Boolean<br>
	 * 异常信息：无<br>
	 */
    canExecute:function(){
    	if(this.modelList.getSize()){    		
    		return true;
    	}
    	return false;
    },
    
    /**
	 * 函数名称：Rainier.UI.V2.CommandPaste.execute<br>
	 * 函数功能：执行命令<br>
	 * 函数返回：无<br>
	 * 异常信息：无<br>
	 */
    execute:function(){
    	//TODO:添加已知models	
    	var _this = this;
    	this.deviceList.each(function(index,deviceModel){
    		_this.rootModel.addChildModel(deviceModel);
    		var className = deviceModel.property.modelProperty.typeName;
    		// if(className == "OverThreeTextModelJson" || className === "TextModelJson2" || className === "TextModelJson3"){
    		// 	className = "TextModelJson";
    		// }
    		for(var i=0;i<data.length;i++){
    			if(data[i].className == className){
    				data[i].addCount += 1;
    			}
    		}
    	});
    	
    	//翻转数组
    	this.copyInfoList.reverse();
    	this.copyInfoList.each(function(index,connInfo){
    		_this.addConnectionModel(connInfo);
    		//$.proxy(_this.addConnectionModel(connInfo),_this);
    	});
    	
    	this.rootEditPart.refreshChildren();
    	this.rootEditPart.getFigure().setCurrentSelection(null);
    	
    	//重新设置model的位置
    	this.resetModelsPosition();
    	
    	//注：当删除的时候，应该先删除连线，在删除元件。
    	_this.editParts.reverse();
    	this.deleteCmd = new Rainier.UI.V2.CommandDeleteMulti(_this.editParts);
    },
    
    /**
	 * 函数名称：Rainier.UI.V2.CommandPaste.undo<br>
	 * 函数功能：撤销命令<br>
	 * 函数返回：无<br>
	 * 异常信息：无<br>
	 */
    undo:function(){
    	this.deleteCmd.execute();
    },
    
    /**
	 * 函数名称：Rainier.UI.V2.CommandPaste.redo<br>
	 * 函数功能：重做命令<br>
	 * 函数返回：无<br>
	 * 异常信息：无<br>
	 */
    redo:function(){
    	this.deleteCmd.undo();
    },
    
    /**
	 * 函数名称：Rainier.UI.V2.CommandPaste.resetModelsPosition<br>
	 * 函数功能：重新设置model的位置<br>
	 * 参数输入：无<br>
	 * 参数输出：无<br>
	 * 函数返回：无<br>
	 * 异常信息：无<br>
	 */
    resetModelsPosition : function(){
    	var _this = this;
    	
    	var oldVerticeList = [];
    	this.connList.each(function(j,model){
    		var editPart = _this.context.findEditPartByModel(model);
    		if(editPart){
    			var oldVertices = editPart.getFigure().getVertices();
	    		oldVertices.each(function(i,vertice){
	    			vertice.x += _this.offset;
	    			vertice.y += _this.offset;
	    		});
	    		oldVerticeList.push(oldVertices.clone());
    		}
    	});
    	if(this.deviceList.getSize() === 1){
    		this.deviceList.each(function(j,model){
    			var editPart = _this.context.findEditPartByModel(model);
    			if(editPart){
    				_this.editParts.add(editPart);
    				
    				editPart.getFigure().select(true);
    				editPart.active();
    				
    				var cmd = new Rainier.UI.V2.CommandMove(editPart);
    				var offsetX = Math.round(Math.random()*40);
    				var offsetY = Math.round(Math.random()*40);
    				cmd.setPosition(_this.mouseDownPos.x + offsetX,_this.mouseDownPos.y + offsetY);
    				cmd.execute();
    			}
    		});
    	}else{
    		var _editPart = this.context.findEditPartByModel(this.deviceList.data[0]);
    		var _x =  _editPart.getFigure().x;
    		var _y = _editPart.getFigure().y;
    		this.deviceList.each(function(j,model){
    			var editPart = _this.context.findEditPartByModel(model);
    			if(editPart){
    				_this.editParts.add(editPart);
    				
    				editPart.getFigure().select(true);
    				editPart.active();
    				
    				var cmd = new Rainier.UI.V2.CommandMove(editPart);
    				var offsetX = editPart.getFigure().x-_x;
    				var offsetY = editPart.getFigure().y-_y;
    				cmd.setPosition(_this.mouseDownPos.x + offsetX,_this.mouseDownPos.y + offsetY);
    				// cmd.setPosition(editPart.getFigure().x + _this.offset,editPart.getFigure().y + _this.offset);
    				cmd.execute();
    			}
    		});
    	}
    	this.connList.each(function(j,model){
    		var editPart = _this.context.findEditPartByModel(model);
    		if(editPart){
    			_this.editParts.add(editPart);
    			
    			var cmd = new Rainier.UI.V2.CommandMoveVertices(editPart);
	    		cmd.updateVertices(oldVerticeList[j]);
	    		cmd.execute();
	    		
	    		editPart.getFigure().select(true);
	    		editPart.active();
    		}
    	});
    },
    
    /**
	 * 函数名称：Rainier.UI.V2.CommandPaste.addConnectionModel<br>
	 * 函数功能：向canva界面上添加对应的connectionmodel对象<br>
	 * 参数输入：conn : 添加的conn对象<br>
	 * 参数输出：无<br>
	 * 函数返回：无<br>
	 * 异常信息：无<br>
	 */
    addConnectionModel : function(connModelInfo){
    	var connType	= connModelInfo.connType;
		var connObj 	= connModelInfo.connModel;
		var sourceModel = connModelInfo.sourceModel;
		var targetModel = connModelInfo.targetModel;
		
		//第一步：把当前连线添加进来
		var conn = connObj.connection;
		conn.clearChildren();
		
		//第二步：恢复连线两端的jointModel
		if(sourceModel){
			var jointModel 		 = sourceModel.jointModel;
			var hybridPort		 = sourceModel.hybirdPort;
			
			var jointModelId	 = jointModel.getUuid();
			
			var jointModelParent  = jointModel.getParent();
			var connJointModelIds = [];
			var connJointModels   = jointModelParent.getChildren();
			connJointModels.forEach(function(connJointModel,index,connJointModels){
				connJointModelIds.push(connJointModel.getUuid());
			})
			//不存在当前model
			if(connJointModelIds.indexOf(jointModelId) === -1){
				jointModel.addPort(hybridPort);
				jointModelParent.addChildModel(jointModel);    					
			}
			
		}
		
		if(targetModel){
			var jointModel 		 = targetModel.jointModel;
			var hybridPort		 = targetModel.hybirdPort;
			
			var jointModelId	 = jointModel.getUuid();
			
			var jointModelParent  = jointModel.getParent();
			var connJointModelIds = [];
			var connJointModels   = jointModelParent.getChildren();
			connJointModels.forEach(function(connJointModel,index,connJointModels){
				connJointModelIds.push(connJointModel.getUuid());
			})
			//不存在当前model
			if(connJointModelIds.indexOf(jointModelId) === -1){
				jointModel.addPort(hybridPort);
				jointModelParent.addChildModel(jointModel);    					
			}
			
		}
		//添加对应的关联关系
		var sourcePort = connObj.sourcePort;
		var targetPort = connObj.targetPort;
		conn.attachSourcePort(sourcePort);
		conn.attachTargetPort(targetPort);
		sourcePort.attachOutgoing(conn);
		targetPort.attachIncoming(conn);
		
		this.rootModel.addConnection(conn);
		this.rootEditPart.refreshChildren();
    },
    
    /**
	 * 函数名称：Rainier.UI.V2.CommandPaste.caculateModelOffset<br>
	 * 函数功能：计算当前鼠标位置，并对鼠标位置进行相应的转换<br>
	 * 参数输入：无<br>
	 * 参数输出：无<br>
	 * 函数返回：转换后的坐标值<br>
	 * 异常信息：无<br>
	 */
    caculateModelOffset : function(){
    	var mouseDownX = this.rootFigure.mouseDownX;
    	var mouseDownY = this.rootFigure.mouseDownY;
    	var mouseDownPos = this.rootFigure.fromDocumentToCanvasCoordinate(mouseDownX, mouseDownY);
    	
    	return mouseDownPos;
    },
	
	/**
	 * 函数名称：Rainier.UI.V2.CommandPaste._removeJointModel<br>
	 * 函数功能：删除连线的 的sourceModel,或者targetModel<br>
	 * 参数输入：jointModel : 需要删除的jointModel<br>
	 * 参数输出：无<br>
	 * 函数返回：无<br>
	 * 异常信息：无<br>
	 */
	 _removeJointModel:function(jointModel){
		jointPort 	  = jointModel.getHybridPorts().get(0);
		var incoming  = jointPort.getIncomings();
		var outgoing  = jointPort.getOutgoings();
		var size 	  = incoming.getSize() + outgoing.getSize();
		if(size<1){
			//说明当前节点可以删除
			var jointModelParent = jointModel.getParent();
			if(jointModelParent){
				jointModelParent.removeChildModel(jointModel);
			}
		}
	 },
	 
	 /**
	 * 函数名称：Rainier.UI.V2.CommandPaste.isSelected<br>
	 * 函数功能：判断当前元件是否被选中<br>
	 * 参数输入：model： 需要判断的元件model<br>
	 * 参数输出：无<br>
	 * 函数返回：flag ：boolean 是否被选中<br>
	 * 异常信息：无<br>
	 */
	 isSelected : function(model){
		 var _this = this;
		 var uuid  = model.getUuid();
		 var flag  = false;
		 var selectModels = _this.context.getSelected();
		 selectModels.each(function(index,selectedModel){
			 var selUuid = selectedModel.getUuid();
			 if(selUuid === uuid){
				 flag = true;
				 return;
			 }
		 });
		 return flag;
	 }
});